package org.zjx.core.nodes;

import lombok.Getter;
import org.zjx.core.DecisionContext;
import org.zjx.core.DecisionNode;
import org.zjx.core.GameAction;

import java.util.List;
import java.util.Random;

/**
 * 随机选择节点 - 从多个候选节点中随机选择一个执行的决策节点
 *
 * 设计特点：
 * 1. 线程安全的随机选择实现
 * 2. 防御性编程确保输入有效性
 * 3. 使用不可变集合保证线程安全
 */
@Getter
public class RandomSelectorNode implements DecisionNode {
    /**
     * 候选决策节点列表
     * 使用不可变集合保证线程安全，
     * 初始化后不能更改列表内容。
     */
    private final List<DecisionNode> candidates;

    /**
     * 随机数生成器
     * 每个节点实例拥有独立的Random实例，
     * 避免多线程竞争导致的性能问题。
     */
    private final Random random;

    /**
     * 构造函数
     *
     * @param candidates 候选决策节点列表(不可为null或空)
     * @throws IllegalArgumentException 如果candidates为null或空
     *
     * 设计考虑：
     * 1. 在构造时验证输入有效性
     * 2. 创建防御性副本保证线程安全
     * 3. 初始化随机数生成器
     */
    public RandomSelectorNode(List<DecisionNode> candidates) {
        if (candidates == null || candidates.isEmpty()) {
            throw new IllegalArgumentException("Candidates list cannot be null or empty");
        }
        // 创建不可修改的副本，保证线程安全
        this.candidates = List.copyOf(candidates);
        // 每个节点实例拥有独立的Random对象
        this.random = new Random();
    }

    /**
     * 执行决策逻辑
     *
     * @param context 决策上下文
     * @return 随机选择的节点的执行结果
     *
     * 执行流程：
     * 1. 从候选列表中随机选择一个节点
     * 2. 调用选中节点的decide方法
     * 3. 返回选中节点的执行结果
     *
     * 注意事项：
     * 1. 虽然构造函数已保证列表非空，但仍做防御性检查
     * 2. 随机选择可能导致非确定性行为
     */
    @Override
    public GameAction decide(DecisionContext context) {
        // 防御性检查(虽然构造函数已保证非空)
        if (candidates.isEmpty()) return null;

        // 随机选择一个节点索引
        // nextInt(n)返回[0, n)范围内的随机整数
        DecisionNode selected = candidates.get(random.nextInt(candidates.size()));

        // 调用选中节点的决策方法并返回结果
        return selected.decide(context);
    }
}